package cn.afterturn.oneopen.controller;

import cn.afterturn.oneopen.model.ApiInfoModel;
import cn.afterturn.oneopen.model.SwaggerProjectModel;
import cn.afterturn.oneopen.service.IApiInfoService;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author by jueyue on 19-1-15.
 */
@RestController
@RequestMapping
public class DocController {

    private static final Logger LOGGER = LoggerFactory.getLogger(DocController.class);

    @Value("${spring.application.name}")
    private String            applicationName;
    @Autowired
    private GatewayProperties gatewayProperties;
    @Autowired
    private IApiInfoService   apiInfoService;
    @Autowired
    RedisTemplate redisTemplate;


    private Map<String, String>          prefixMap          = new HashMap<>();
    /**
     * 服务列表
     */
    private List<ServiceInstance>        serviceInstanceList;
    /**
     * 服务列表
     */
    private Map<String, ServiceInstance> serviceInstanceMap = new HashMap<>();


    @GetMapping("/services")
    public List<SwaggerProjectModel> serviceUrl() {
        List<ServiceInstance>     serviceInstanceList = getServiceInstanceList();
        List<SwaggerProjectModel> services            = new ArrayList<>();
        SwaggerProjectModel       model;
        for (int i = 0; i < serviceInstanceList.size(); i++) {
            try {
                List<SwaggerProjectModel> tempList = JSON.parseArray(HttpUtil.get(serviceInstanceList.get(i).getUri().toString() + "/swagger-resources", 1000), SwaggerProjectModel.class);
                for (int j = 0; j < tempList.size(); j++) {
                    model = tempList.get(j);
                    model.setName(serviceInstanceList.get(i).getServiceId() + ":" + model.getName());
                    model.setUrl("/group/" + serviceInstanceList.get(i).getServiceId() + "/" + getGroup(model.getUrl()));
                    model.setPrefix(prefixMap.get(serviceInstanceList.get(i).getServiceId()));
                    services.add(model);
                }

            } catch (Exception e) {
            }
        }

        return services;
    }

    private String getGroup(String url) {
        return HttpUtil.decodeParamMap(url, "UTF8").get("group");
    }

    @GetMapping("/group/{serviceId}/{group}")
    public String group(@PathVariable String serviceId, @PathVariable String group) {
        String data = (String) redisTemplate.opsForValue().get("SWAGGER:DOC");
        if (StringUtils.isEmpty(data)) {
            String json = HttpUtil.get(serviceInstanceMap.get(serviceId).getUri().toString() + "/v2/api-docs");
            data = handlerResult(json);
            redisTemplate.opsForValue().set("SWAGGER:DOC", data, 1, TimeUnit.DAYS);
        }
        return data;
    }

    private String handlerResult(String json) {
        Map map = JSON.parseObject(json, Map.class);
        //判断哪些可以使用
        Map          paths = (Map) map.get("paths");
        List<String> keys  = new ArrayList<>();
        Set<String>  tags  = new HashSet<>();
        keys.addAll(paths.keySet());
        for (String key : keys) {
            try {
                ApiInfoModel apiInfoModel = apiInfoService.getOne(new QueryWrapper<ApiInfoModel>().eq("url", key));
                if (apiInfoModel != null && apiInfoModel.getStatus() == 1) {
                    Map         methods    = (Map) paths.get(key);
                    Set<String> methodKeys = methods.keySet();
                    for (String methodKey : methodKeys) {
                        tags.add(apiInfoModel.getTag());
                        ((Map) methods.get(methodKey)).put("tags", new String[]{apiInfoModel.getTag()});
                        if (apiInfoModel.getName() == null) {
                            apiInfoModel.setName(((Map) methods.get(methodKey)).get("summary").toString());
                            apiInfoService.updateById(apiInfoModel);
                        }
                    }
                } else {
                    paths.remove(key);
                }
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
                paths.remove(key);
            }
        }
        //使用数据的tag统一标准
        /*List list = (List) map.get("tags");
        for (int i = list.size() - 1; i > -1; i--) {
            String name = ((Map) list.get(i)).get("name").toString();
            if (!tags.contains(name)) {
                list.remove(i);
            }
        }*/
        List<Map> list = new ArrayList<>();
        for (String tag : tags) {
            Map tagObj = new HashMap();
            tagObj.put("name", tag);
            tagObj.put("description", tag);
            list.add(tagObj);
        }
        map.put("tags", list);
        return JSON.toJSONString(map);
    }


    private List<ServiceInstance> getServiceInstanceList() {
        return serviceInstanceList;
    }


    @PostConstruct
    private void getPrefixMap() {
        serviceInstanceList = new ArrayList<>();
        RouteDefinition route;
        for (int i = 0; i < gatewayProperties.getRoutes().size(); i++) {
            route = gatewayProperties.getRoutes().get(i);
            for (int j = 0; j < route.getPredicates().size(); j++) {
                serviceInstanceList.add(new DefaultServiceInstance(route.getId(),
                        route.getUri().getHost(), route.getUri().getPort(), false));
                serviceInstanceMap.put(route.getId(), serviceInstanceList.get(serviceInstanceList.size() - 1));
                if (route.getPredicates().get(j).getName().equalsIgnoreCase("path")) {
                    prefixMap.put(route.getId(), getPrefix(route.getPredicates().get(j).getArgs()));
                }
            }
        }
    }

    private String getPrefix(Map<String, String> args) {
        for (String val : args.values()) {
            return val.substring(1, val.indexOf("/", 1));
        }
        return "";
    }

}
